package com.kgc.est.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kgc.est.constants.Constants;
import com.kgc.est.constants.ResultEnum;
import com.kgc.est.dto.UsersDto;
import com.kgc.est.pojo.Users;
import com.kgc.est.mapper.UsersMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kgc.est.request.LoginSmsReq;
import com.kgc.est.utils.Result;
import com.kgc.est.utils.ResultUtils;
import com.kgc.est.utils.UUIDUtils;
import com.kgc.est.utils.UrlUtils;
import com.kgc.est.utils.redis.RedisKeyUtils;
import com.kgc.est.utils.redis.RedisUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author szq
 * @since 2021-10-19
 */
@RestController
@RequestMapping("/user")
public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users>{

    Logger log = LoggerFactory.getLogger(UsersServiceImpl.class);

    @Autowired
    private RedisUtils redisUtils;


    /**
     * 短信登录的实现流程
     *      验证
     *          手机号
     *          验证码
     *      到数据库中查询用户是否存在
     *          如果不存在，把这个用户保存到数据库中
     *
     *      生成token：设置token有效期
     *              前缀key：est_token_xxxxxx：
     *                  value： 用户信息
     *
     * @param loginSmsReq
     * @return
     */
    @PostMapping("/loginSms")
    public Result<Map<String,Object>> loginSms(@RequestBody LoginSmsReq loginSmsReq){

        //验证手机号
        if (!checkPhone(loginSmsReq.getPhone())){
            return ResultUtils.returnFail("手机号不正确", ResultEnum.FAIL.getCode());
        }

        //验证短信验证码  是否为空，是否正确
        if (!checkSmsCode(loginSmsReq.getPhone(),loginSmsReq.getSms())){
            return ResultUtils.returnResult(ResultEnum.FAIL_VERIFY);
        }
        //查询用户是否存在
        QueryWrapper<Users> qw = new QueryWrapper<Users>();
        qw.eq("account",loginSmsReq.getPhone());
        Users users = this.getOne(qw);

        if (null == users){
            //创建一个user对象，然后保存到数据库中
            users = new Users();
            users.setAccount(loginSmsReq.getPhone());
            users.setUserName(loginSmsReq.getPhone());
            users.setIsAuthentication(0);
            this.save(users);
            log.info("users对象保存成功..{}",users);
        }

        //根据用户信息生成token，并把token保存到redis中
        String token = savaToken(users);

        //把token信息保存到map中返回给服务消费者
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("token",token);
        return ResultUtils.returnDataSuccess(map);
    }


    /**
     * 根据token获取用户信息
     * @param token
     * @return
     */
    @GetMapping("/info")
    public Result<UsersDto> info(@RequestParam("token") String token){
        //根据token从redis中取出用户信息
        String key = RedisKeyUtils.formatKeyWithPrefix(Constants.Redis.PREFIX_TOKEN, token);

        String value = redisUtils.getValue(key);
        //通过反序列化把json串变成user对象
        Users users = JSON.parseObject(value, Users.class);

        if (null == users){
            return null;
        }
        //把用户信息存储到UserDto对象中
        UsersDto usersDto = new UsersDto(users);
        usersDto.setToken(token);
        return ResultUtils.returnDataSuccess(usersDto);
    }


    /**
     *验证用户是否已经使用微信登录过二手兔
     *      1.通过openid查询数据库
     *          如果返回的user为null
     *              那么我们就第三次请求微信，拿到用户数据
     *              并且把数据存储到数据库中
     *          如果返回user不为null
     *              那么就直接生成用户信息并JSON化后存储到redis中
     * @param access_token
     * @param openid
     * @return
     */
    @GetMapping("/loginWechat")
    public Map<String,Object> loginWechat(@RequestParam("access_token") String access_token,@RequestParam("openid") String openid){
        //查询数据库
        //拼接查询条件
        QueryWrapper<Users> qw = new QueryWrapper<>();
        qw.eq("openid",openid);
        //执行查询并接收查询结果
        Users users = this.getOne(qw);
        //判断查询结果
        //如果数据库中不存在用户信息
        if (null == users){
            //向微信发送第三次请求，获取用户信息
            Map<String, Object> map = wechatUserInfo(access_token, openid);
            /**
             * {
             * "openid":"OPENID",
             * "nickname":"NICKNAME",  //昵称
             * "sex":1, //性别
             * "province":"PROVINCE", //省份
             * "city":"CITY",  //城市
             * "country":"COUNTRY", //国家
             * //图像路径
             * "headimgurl": "https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
             * "privilege":[
             * "PRIVILEGE1",
             * "PRIVILEGE2"
             * ],
             * "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
             *
             * }
             */

            log.info("二手兔第三次向微信发送请求：{}",map);
            users = new Users();
            users.setOpenId(openid);

            if (null != map.get("nickname")){
                users.setUserName(map.get("nickname").toString());
            }
            if (null != map.get("sex")){
                users.setSex(Integer.parseInt(map.get("sex").toString()));
            }
            if (null != map.get("headimgurl")){
                users.setFaceUrl(map.get("headimgurl").toString());

            }
            users.setIsAuthentication(0);

            //把用户信息保存到数据库中
            this.save(users);
        }

        //如果数据库中存在用户信息
        //生成一个token作为key，users信息JSON化后作为value，并且保存到redis中
        String token = savaToken(users);

        //把token和用户信息存储到map中返回
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("token",token);
        resultMap.put("userInfo",users.getUserName());

        return resultMap;
    }



    /**
     * 验证手机格式是否正确
     * @param phone
     * @return
     */
    private boolean checkPhone(String phone){
        //验证手机号不为空
        if(!StringUtils.isBlank(phone)){
            return phone.matches(Constants.PHONE_REGSTR);
        }
        return false;
    }

    /**
     * 验证验证码是否正确
     * @param phone
     * @param sms 用户从页面传递过来的验证码
     * @return
     */
    public boolean checkSmsCode(String phone,String sms){
        //如果不为空，那么就去redis中取
        if (!StringUtils.isBlank(sms)){
            //从redis中取出短信验证码
            String code = getRedisValue(phone);
            return sms.equals(code);
        }

        return false;
    }


    /**
     *  根据手机账号获取redis中的短信验证码
     * @param phone
     * @return
     */
    public String getRedisValue(String phone){
        String key = RedisKeyUtils.formatKeyWithPrefix(Constants.Redis.PREFIX_SMS,
                Constants.Sms.TYPE_REGIST_OR_LOGIN.toString(),phone);
        return redisUtils.getValue(key);
    }


    /**
     * 把一个对象信息使用token保存到redis中
     * @param users
     * @return
     */
    public String savaToken(Users users){
        String token = UUIDUtils.create32BitUUID();

        //保存token信息到数据库
        String key = RedisKeyUtils.formatKeyWithPrefix(Constants.Redis.PREFIX_TOKEN, token);
        //设置有效期半小时
        redisUtils.putValue(key, JSON.toJSONString(users),Constants.Duration.HALF_AN_HOUR);

        return token;
    }


    public Map<String,Object> wechatUserInfo(String accessToken,String openId){
        Map<String,Object> userInfo = null;

        try {
            String json = UrlUtils.loadURL("https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken
                    + "&openid=" + openId);
            userInfo = JSON.parseObject(json, Map.class);
        }catch (Exception e){
            log.info("授权失败",e.getMessage());
        }
        return userInfo;
    }


}
